﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MetaCollection.Framework.Model;
using System.Security.Principal;
using System.Web.Security;

namespace MetaCollection.Framework.Security
{
	/// <summary>
	/// A collection of permissions for an identity.  This collection is used when evaluating 
	/// access to the collection items.
	/// </summary>
	public class MetaPrincipal : IPrincipal
	{
		/// <summary>
		/// A claim type that represents a role for role based security permissions
		/// </summary>
		public const string RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
		/// <summary>
		/// A claim type that represents the name of an identity
		/// </summary>
		public const string NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name";

		/// <summary>
		/// Returns the MetaPrincipal that represents the MetaCollection System itself.
		/// </summary>
		public static MetaPrincipal SystemPrincipal { get { return new MetaPrincipal(new GenericIdentity("SYSTEM")); } }

		/// <summary>
		/// Contains a list of all the claims associated with this principal
		/// </summary>
		private List<IItemClaim> m_Claims;

		/// <summary>
		/// Initializes a new Collection permission set using the given identity
		/// </summary>
		/// <param name="identity">the identity associated with this permission set</param>
		public MetaPrincipal(IIdentity identity)
		{
			if (identity == null)
				throw new ArgumentNullException("identity");
			Identity = identity;
			m_Claims = new List<IItemClaim>();
			m_Claims.Add(new ItemClaim { Id = Guid.Empty, ClaimType = NameClaimType, Rights = AccessRights.Unknown, ClaimValue = identity.Name });
		}
		/// <summary>
		/// Initializes a new Collection permission set using the given identity. Assigns the claims
		/// to the current collection permission set instance
		/// </summary>
		/// <param name="identity">identity for the collectionpermissions set</param>
		/// <param name="claims">claims to initialize with</param>
		public MetaPrincipal(IIdentity identity, IEnumerable<IItemClaim> claims)
		{
			if (identity == null)
				throw new ArgumentNullException("identity");
			Identity = identity;
			m_Claims = new List<IItemClaim>();
			m_Claims.Add(new ItemClaim { Id = Guid.Empty, ClaimType = NameClaimType, Rights = AccessRights.Unknown, ClaimValue = identity.Name });
			if (claims != null)
				m_Claims.AddRange(claims);
		}

		/// <summary>
		/// Claims associated with this principal
		/// </summary>
		public IEnumerable<IItemClaim> Claims { get { return m_Claims.AsReadOnly(); } }

		/// <summary>
		/// The identity assocaited with this set of permissions.
		/// </summary>
		public IIdentity Identity { get; private set; }

		#region IPrincipal Members

		/// <summary>
		/// Returns true if the collection permissions set contains any claims of type role with a value that matches <paramref name="role"/>
		/// </summary>
		/// <param name="role">the role to match</param>
		/// <returns>true if this set of permissions contains <paramref name="role"/></returns>
		public bool IsInRole(string role)
		{
			var access = from c in m_Claims
						 where (c.ClaimType == RoleClaimType) && (c.ClaimValue.Equals(role, StringComparison.OrdinalIgnoreCase))
						 select c;
			return access.Any();
		}

		#endregion
	}
}
